//Router.cpp
#include "Router.h"
//////////////////////////////////////////////////////////
//
//	Router Constructor
//	arguements:
//		fn: A string of log file name
//
//////////////////////////////////////////////////////////

Router::Router(char *fn)		//Constructor
{
	WSADATA wsadata;
	HOSTENT* hp;				
	char peer_name1[MAXHOSTNAMELEN], peer_name2[MAXHOSTNAMELEN];
	SOCKADDR_IN sa_in;

	FileBuf.empty=true;

	try 
	{                  
		if (WSAStartup(0x0202,&wsadata)!=0)
			throw "Error in starting WSAStartup()\n";
	}

	//Display any needed error response.
	catch (char *str) { cerr<<str<<":"<<dec<<WSAGetLastError()<<endl; return;}

	//Get Host name
	gethostname(localhost,MAXHOSTNAMELEN);
	cout<<"Router starting on host:"<<localhost<<endl<<flush;

	//Open the log file
	fout.open(fn);

	try
	{
		//Create the Udp Sock1
		if((Sock1 = socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET) 
			throw "Create UDP Socket1 failed\n";

		//Fill-in UDP Port and Address info.
		sa_in.sin_family = AF_INET;
		sa_in.sin_port = htons(ROUTER_PORT1);
		sa_in.sin_addr.s_addr = htonl(INADDR_ANY);

		//Bind the UDP port1
		if (bind(Sock1,(LPSOCKADDR)&sa_in,sizeof(sa_in)) == SOCKET_ERROR)
			throw "can't bind the socket1";

		//Create the Udp Sock2
		if((Sock2 = socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET) 
			throw "Create UDP Socket2 failed\n";

		//Fill-in UDP Port and Address info.
		sa_in.sin_family = AF_INET;
		sa_in.sin_port = htons(ROUTER_PORT2);
		sa_in.sin_addr.s_addr = htonl(INADDR_ANY);

		//Bind the UDP port2
		if (bind(Sock2,(LPSOCKADDR)&sa_in,sizeof(sa_in)) == SOCKET_ERROR)
			throw "can't bind the socket2";

		cout<<"\nPlease enter the first peer host name:"<<flush;		//enter the dropping rate.
		cin>>peer_name1;
		cout<<"\nPlease enter the second peer host name:"<<flush;		//enter the dropping rate.
		cin>>peer_name2;
		cout<<"\nPlease enter the drop rate:"<<flush;		//enter the dropping rate.
		cin>>damage_rate;
		cout<<"\nPlease enter the delay rate:"<<flush;		//enter the dropping rate.
		cin>>delay_rate;

		//creat peer host1
		if((hp=gethostbyname(peer_name1)) == NULL) 
			throw "get server name failed\n";
		memset(&sa_in_peer1,0,sizeof(sa_in_peer1));
		memcpy(&sa_in_peer1.sin_addr,hp->h_addr,hp->h_length);
		sa_in_peer1.sin_family = hp->h_addrtype;   
		sa_in_peer1.sin_port = htons(PEER_PORT1);

		//creat peer host2
		if((hp=gethostbyname(peer_name2)) == NULL) 
			throw "get client name failed\n";
		memset(&sa_in_peer2,0,sizeof(sa_in_peer2));
		memcpy(&sa_in_peer2.sin_addr,hp->h_addr,hp->h_length);
		sa_in_peer2.sin_family = hp->h_addrtype;   
		sa_in_peer2.sin_port = htons(PEER_PORT2);

		if (TRACE)
		{
			fout<<"Peer host 1: "<<peer_name1<<endl;
			fout<<"Peer host 2: "<<peer_name2<<endl;
			fout<<"Damage Rate: "<<damage_rate<<endl;
		}
	}		
	catch (char *str) {cerr<<str<<":"<<dec<<WSAGetLastError()<<endl; exit(1);}

	srand( (unsigned)time( NULL ) );
}

//////////////////////////////////////////////////////////
//
//	Router::IsDamage
//		The function that generates random damages according to damage rate.
//
//////////////////////////////////////////////////////////

bool Router::IsDamage() const
{	
	return ( (((float)rand())/RAND_MAX) < ((float)damage_rate/100));
}

//////////////////////////////////////////////////////////
//
//	Router::IsDelayed
//		The function that generates random delayed according to delay rate.
//
//////////////////////////////////////////////////////////

bool Router::IsDelayed() const
{	
	return ( (((float)rand())/RAND_MAX) < ((float)delay_rate/100));
}

//////////////////////////////////////////////////////////
//
//	Router::Run
//		The function receives packets from peer hosts and forwards to destinations.  
//		It also drops packets and stores delayed packets for future sending.
//		It calls SendProc to send delayed packets.
//
//////////////////////////////////////////////////////////

void Router::Run()
{
	fd_set readfds;
	struct timeval *tp=new timeval;
	SOCKADDR from;
	int RetVal, fromlen, recvlen, wait_count;
	EVENT_LIST temp;
	DWORD CurrentTime, count1, count2;

	count1=0; 
	count2=0;
	wait_count=0;
	tp->tv_sec=0;
	tp->tv_usec=TIMEOUT_USEC;

	while (1)
	{
		try
		{
			FD_ZERO(&readfds);
			FD_SET(Sock1,&readfds);
			FD_SET(Sock2,&readfds);
			fromlen=sizeof(from);
			if((RetVal=select(1,&readfds,NULL,NULL,tp))==SOCKET_ERROR)	//check for incoming packets.
				throw "Timer error!";
			else if(RetVal>0)	//There are incoming packets.
			{
				if(!FileBuf.empty) wait_count++;
				if(FD_ISSET(Sock1, &readfds))	//incoming packet from peer host 1
				{
					if((recvlen=recvfrom(Sock1, temp.Buffer, sizeof(temp.Buffer), 0, &from, &fromlen))==SOCKET_ERROR)
						throw " Get buffer error!";
					if (TRACE)
					{
						fout<<"Router: Receive packet "<<count1<<" from peer host 1"<<endl;
						cout<<"Router: Receive packet "<<count1<<" from peer host 1"<<endl;
					}
					temp.count=count1;
					count1++;
					temp.destination=2;
				}
				else if(FD_ISSET(Sock2, &readfds))	//incoming packet from peer host 2
				{
					if((recvlen=recvfrom(Sock2, temp.Buffer, sizeof(temp.Buffer), 0, &from, &fromlen))==SOCKET_ERROR)
						throw " Get buffer error!";
					if (TRACE)
					{
						fout<<"Router: Receive packet "<<count2<<" from peer host 2"<<endl;
						cout<<"Router: Receive packet "<<count2<<" from peer host 2"<<endl;
					}
					temp.count=count2;
					count2++;
					temp.destination=1;
				}
				else continue;
				temp.len=recvlen;
				CurrentTime=GetTickCount();
				if(FileBuf.empty&&IsDelayed())		//if the packet is delayed.
				{
					FileBuf=temp;
					FileBuf.empty=false;
					if (TRACE)
					{
						fout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been delayed!"<<endl;
						cout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been delayed!"<<endl;
					}
				}
				else if(IsDamage())	//if the packet is dropped: dropping packet by no forwarding the packet.
				{
					if (TRACE)
					{
						fout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been dropped by router!"<<endl;
						cout<<"Router: Packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1)<<" has been dropped by router!"<<endl;
					}
				}
				else		//otherwise, packet is forwarded to destination
				{
					if(temp.destination==1)	//forward packets received from 2 to 1.
					{
						if(sendto(Sock1, temp.Buffer, temp.len,0,(SOCKADDR*)&sa_in_peer1,sizeof(sa_in_peer1))==SOCKET_ERROR)
							throw "Send packet error!";
						if (TRACE)
						{
							fout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
							cout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
						}
						if(!FileBuf.empty&&FileBuf.destination==1)
						{
							wait_count=0;
							SendProc();
						}
					}
					else
					{	//forward packets received from 1 to 2.
						if(sendto(Sock2, temp.Buffer, temp.len,0,(SOCKADDR*)&sa_in_peer2,sizeof(sa_in_peer2))==SOCKET_ERROR)
							throw "Send packet error1";
						if (TRACE)
						{
							fout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
							cout<<"Router: Send packet "<<temp.count<<" received from peer host "<<(temp.destination==1?2:1) <<" to host "<<temp.destination<<endl;
						}
						if(!FileBuf.empty&&FileBuf.destination==2)
						{
							wait_count=0;
							SendProc();
						}
					}	
				}
			}
			else //If there is no incoming packet and there is a delayed packets storing in buffer for 3 cycle times (about 0.9 second), call SendProc to send delayed packet.
			{		
				if(!FileBuf.empty)
				{
					wait_count++;
					if(wait_count>=3)
					{
						SendProc();
						wait_count=0;
					}
				}
			}
		} //end of try
		catch(char *str) {cerr<<str<<":"<<dec<<WSAGetLastError()<<endl;}
	}//end of while
}

//////////////////////////////////////////////////////////
//
//	Router::SendProc
//		Send delayed packets to the destinations.
//
//////////////////////////////////////////////////////////

void Router::SendProc()
{
	try
	{
		if(FileBuf.destination==1)
		{
			if(sendto(Sock1, FileBuf.Buffer, FileBuf.len,0,(SOCKADDR*)&sa_in_peer1,sizeof(sa_in_peer1))==SOCKET_ERROR)
				throw "Send packet error!";
		}
		else
		{
			if(sendto(Sock2, FileBuf.Buffer, FileBuf.len,0,(SOCKADDR*)&sa_in_peer2,sizeof(sa_in_peer2))==SOCKET_ERROR)
				throw "Send packet error!";
		}
		if (TRACE)
		{
			fout<<"Router: Send delayed packet "<<FileBuf.count<<" received from peer host "<<(FileBuf.destination==1?2:1)<<" to host "<<FileBuf.destination<<endl;
			cout<<"Router: Send delayed packet "<<FileBuf.count<<" received from peer host "<<(FileBuf.destination==1?2:1)<<" to host "<<FileBuf.destination<<endl;
		}
	}
	catch(char *str){cerr<<str<<":"<<dec<<WSAGetLastError()<<endl;}
	FileBuf.empty=true;
}

//////////////////////////////////////////////////////////
//
//	Router Destructor
//	arguements:
//		fn: A string of log file name
//
//////////////////////////////////////////////////////////

Router :: ~Router()
{
	closesocket(Sock1);
	closesocket(Sock2);

	/* When done, uninstall winsock.dll (WSACleanup()) and exit */ 
	WSACleanup();  

	//close log file
	fout.close();
}

//////////////////////////////////////////////////////////
//
//	Main function
//
//////////////////////////////////////////////////////////

void main()
{
	Router router;
	router.Run();
}
